<template>
  <div :class="prefixCls">
    <a-form-item-rest>
      <a-popover
        trigger="click"
        placement="bottom"
        :getPopupContainer="getPopContent"
        :overlayClassName="`${prefixCls}__overlay`"
        @openChange="handleFetch"
      >
        <template #content>
          <a-skeleton active :loading="st.skLoading" />
          <a-list
            size="small"
            :class="`${prefixCls}_list`"
            :style="`width:` + st.width + `px`"
            :data-source="getOptions"
            :pagination="getPagination"
            :loading="loadingRef"
          >
            <!--            v-model:value="st.searchKey"-->
            <template #header>
              <a-input-search allowClear placeholder="请输入要搜索内容" @search="doSearch" />
            </template>
            <template #renderItem="{ item }">
              <a-list-item
                class="hover:bg-gray-50 border-radius-base"
                :class="selectedRef == item.value ? 'select-bg' : ''"
              >
                <div class="cursor-pointer" @click="handleTitleClick(item)">{{ item.title }}</div>
              </a-list-item>
            </template>
          </a-list>
        </template>

        <a-input
          allowClear
          :value="st.labelname"
          readOnly
          placeholder="请选择"
          class="cursor-pointer"
        >
          <template #clearIcon>
            <div @click.stop="doClearInput">
              <CloseCircleFilled />
            </div>
          </template>
          <template #prefix v-if="loading">
            <LoadingOutlined spin />
          </template>
          <template #suffix>
            <DownOutlined :style="{ color: '#000000', opacity: 0.25 }" />
          </template>
        </a-input>
      </a-popover>
    </a-form-item-rest>
  </div>
</template>
<script setup lang="ts">
  import { reactive, ref, PropType, computed, unref, watch } from 'vue';
  import {
    Popover as APopover,
    List as AList,
    ListItem as AListItem,
    InputSearch as AInputSearch,
    Form,
    Skeleton as ASkeleton,
  } from 'ant-design-vue';
  import { DownOutlined, LoadingOutlined, CloseCircleFilled } from '@ant-design/icons-vue';
  import { useDesign } from '/@/hooks/web/useDesign';
  import { propTypes } from '/@/utils/propTypes';
  import { assign, get, omit, isFunction, isEmpty, isNil } from 'lodash-es';
  import componentSetting from '@/settings/componentSetting';
  import { useRuleFormItem } from '@/hooks/component/useFormItem';
  import { nodListScene } from '@/settings/NodListScene';

  const AFormItemRest = Form.ItemRest;
  defineOptions({
    name: 'Nodlist',
  });
  const props = defineProps({
    value: propTypes.oneOfType([String, Number]),
    api: {
      type: Function as PropType<(arg?: any) => Promise<[]>>,
      default: null,
    },
    // api params
    params: propTypes.any.def({}),

    labelField: propTypes.string.def('name'),
    valueField: propTypes.string.def('id'),
    immediate: propTypes.bool.def(true),
    alwaysLoad: propTypes.bool.def(false),
    placeholder: propTypes.string.def('请选择所属用户'),
    initTitle: propTypes.string.def(''),
    scene: propTypes.string.def(''),
  });
  const emit = defineEmits(['options-change', 'change', 'update:value']);
  const { prefixCls } = useDesign('nodlist');
  const loadingRef = ref(false);
  const options = ref<any[]>([]);
  const st = reactive({
    width: 0,
    labelname: props.initTitle,
    isinit: false,
    total: 0,
    searchKey: '',
    skLoading: true,
  });
  const emitData = ref<[]>([]);
  const [state] = useRuleFormItem(props, 'value', 'change', emitData);
  const loading = ref(false);
  const selectedRef = ref('');
  // 首次是否加载过了
  const isFirstLoaded = ref(false);
  const pageSize = 5;
  const { pageField, sizeField, listField, totalField } = componentSetting.table.fetchSetting;

  const getOptions = computed(() => {
    let { labelField, valueField, scene } = props;
    if (!isEmpty(scene)) {
      const sceneMap = nodListScene(scene);
      if (!isNil(sceneMap)) {
        labelField = sceneMap.labelField;
        valueField = sceneMap.valueField;
      }
    }

    let data = unref(options).reduce((prev, next: any) => {
      if (next) {
        const value = get(next, valueField as string);

        prev.push({
          ...omit(next, [labelField as string, valueField as string]),
          title: get(next, labelField as string),
          value: value,
        });
      }
      return prev;
    }, []);
    return data.length > 0 ? data : [];
  });

  async function fetch(page: number = 1) {
    loadingRef.value = true;
    let api = props.api;
    if (!isEmpty(props.scene)) {
      const sceneMap = nodListScene(props.scene);
      if (!isNil(sceneMap)) {
        api = sceneMap.api;
      }
    }
    if (!api || !isFunction(api) || loading.value) return;
    options.value = [];

    try {
      const param = {};
      param[pageField] = page;
      param[sizeField] = pageSize;
      param['searchKey'] = st.searchKey;
      loading.value = true;
      const res = await api(assign(param, props.params));
      loadingRef.value = false;
      isFirstLoaded.value = true;
      st.skLoading = false;
      options.value = res[listField];
      st.total = res[totalField];
      return;
    } catch (error) {
      console.warn(error);
    } finally {
      loading.value = false;
    }
  }

  const getPopContent = (triggerNode: HTMLElement) => {
    st.width = triggerNode.offsetWidth - 25;
    return document.body;
  };
  const getPagination = computed(() => {
    if (options.value.length > 0) {
      return {
        size: 'small',
        total: st.total,
        pageSize,
        showTotal: (total) => {
          return `共${total}条`;
        },
        onChange(page) {
          fetch(page);
        },
      };
    } else {
      return false;
    }
  });

  async function handleFetch(visible: boolean) {
    if (visible) {
      await fetch();
      if (props.alwaysLoad) {
        await fetch();
      } else if (!props.immediate && !unref(isFirstLoaded)) {
        await fetch();
      }
    }
  }

  const handleTitleClick = (item) => {
    st.labelname = item.title;
    selectedRef.value = item.value;
    state.value = item.value;
    emit('update:value', item.value);
  };

  const doClearInput = () => {
    st.labelname = '';
    selectedRef.value = '';
    state.value = '';
    emit('update:value', '');
  };
  const doSearch = async () => {
    await fetch(1);
  };
  watch(
    () => props.initTitle,
    (v) => {
      if (!isNil(v)) {
        st.labelname = v;
      }
    },
  );
</script>
<style scoped lang="less">
  ::v-deep(.ant-list-item) {
    padding: 5px 8px;
  }

  .select-bg {
    @apply bg-gray-200;
  }
</style>
